package cn.lijiajia3515.cairo.captcha.image.graph;

import cn.hutool.core.util.RandomUtil;
import cn.lijiajia3515.cairo.captcha.image.ImageCaptcha;
import lombok.extern.slf4j.Slf4j;

import java.awt.*;
import java.awt.geom.CubicCurve2D;
import java.awt.geom.QuadCurve2D;

/**
 * 抽象 画 验证码图像
 */
@Slf4j
public abstract class AbstractGraphImageCaptchaHandler implements GraphImageHandler {
	// 使用颜色
	protected int[][] color = {
		{0, 135, 255},
		{51, 153, 51},
		{255, 102, 102},
		{255, 153, 0},
		{153, 102, 0},
		{153, 102, 153},
		{51, 153, 153},
		{102, 102, 255},
		{0, 102, 204},
		{204, 51, 51},
		{0, 153, 204},
		{0, 51, 102}
	};

	/**
	 * 字体
	 */
	protected String[] fontFamilyNames = new String[]{
		"Arial",
		"Action",
		"Consolas",
	};

	public AbstractGraphImageCaptchaHandler() {

	}

	public AbstractGraphImageCaptchaHandler(int[][] color, String[] fontFamilyNames) {
		this.color = color;
		this.fontFamilyNames = fontFamilyNames;
	}

	/**
	 * 获取 字节数组 图片
	 *
	 * @return 图片字节
	 */
	public abstract ImageCaptcha.ImageCaptchaDetail getDetail(GraphImageArgs args);


	/**
	 * 随机颜色
	 *
	 * @return 颜色
	 */
	protected Color color() {
		int[] color = this.color[RandomUtil.randomInt(this.color.length)];
		return new Color(color[0], color[1], color[2]);
	}

	/**
	 * 随机字体
	 *
	 * @return 字体
	 */
	protected Font font() {
		String fontName = fontFamilyNames[RandomUtil.randomInt(fontFamilyNames.length)];
		Font font = new Font(fontName, Font.BOLD, 32);
		log.trace("font: {}", font);
		return font;
	}


	/**
	 * 随机画干扰圆
	 *
	 * @param num    数量
	 * @param width  宽度
	 * @param height 高度
	 * @param g      Graphics2D
	 */
	protected void drawOval(int num, int width, int height, Graphics2D g) {
		drawOval(num, null, width, height, g);
	}

	/**
	 * 随机画干扰圆
	 *
	 * @param num    数量
	 * @param color  颜色
	 * @param width  画布宽度
	 * @param height 画布高度
	 * @param g      Graphics2D
	 */
	protected void drawOval(int num, Color color, int width, int height, Graphics2D g) {
		for (int i = 0; i < num; i++) {
			g.setColor(color == null ? color() : color);
			int w = 5 + RandomUtil.randomInt(10);
			g.drawOval(RandomUtil.randomInt(width - 25), RandomUtil.randomInt(height - 15), w, w);
		}
	}

	/**
	 * 随机画贝塞尔曲线
	 *
	 * @param num    数量
	 * @param width  宽度
	 * @param height 高度
	 * @param g      Graphics2D
	 */
	protected void drawBesselLine(int num, int width, int height, Graphics2D g) {
		drawBesselLine(num, null, width, height, g);
	}

	/**
	 * 随机画贝塞尔曲线
	 *
	 * @param num    数量
	 * @param color  颜色
	 * @param width  画板宽度
	 * @param height 画板高度
	 * @param g      2d 画笔
	 */
	protected void drawBesselLine(int num, Color color, int width, int height, Graphics2D g) {
		for (int i = 0; i < num; i++) {
			g.setColor(color == null ? color() : color);
			int x1 = 5, y1 = RandomUtil.randomInt(5, height / 2);
			int x2 = width - 5, y2 = RandomUtil.randomInt(height / 2, height - 5);
			int ctrlx = RandomUtil.randomInt(width / 4, width / 4 * 3), ctrly = RandomUtil.randomInt(5, height - 5);

			if (RandomUtil.randomInt(2) == 0) {
				int ty = y1;
				y1 = y2;
				y2 = ty;
			}

			if (RandomUtil.randomInt(2) == 0) {
				// 二阶贝塞尔曲线
				QuadCurve2D shape = new QuadCurve2D.Double();
				shape.setCurve(x1, y1, ctrlx, ctrly, x2, y2);
				g.draw(shape);
			} else {
				// 三阶贝塞尔曲线
				int ctrlx1 = RandomUtil.randomInt(width / 4, width / 4 * 3), ctrly1 = RandomUtil.randomInt(5, height - 5);
				CubicCurve2D shape = new CubicCurve2D.Double(x1, y1, ctrlx, ctrly, ctrlx1, ctrly1, x2, y2);
				g.draw(shape);
			}
		}
	}
}
